package com.xu.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.xu.base.enums.ResponseCodeEnum;
import com.xu.base.model.BaseSelectVo;
import com.xu.base.utils.AssertUtils;
import com.xu.mybatis.model.PageInfo;
import com.xu.redis.service.SequenceService;
import com.xu.security.utils.SecurityUtils;
import com.xu.system.constant.Constants;
import com.xu.system.constant.FileCodeConstants;
import com.xu.system.enums.SequenceEnum;
import com.xu.system.model.convert.RoleConvert;
import com.xu.system.model.convert.UserConvert;
import com.xu.system.model.entity.SysRole;
import com.xu.system.model.entity.SysUser;
import com.xu.system.model.pojo.role.*;
import com.xu.system.model.pojo.user.UserSimpleVo;
import com.xu.system.model.pojo.user.UserTranslateBo;
import com.xu.system.service.IFileService;
import com.xu.system.service.IRoleService;
import com.xu.system.service.db.*;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 角色服务
 *
 * @Author: 许乾伟
 * @Date: 2024/12/17 16:00
 */
@Service
public class RoleServiceImpl implements IRoleService {
    @Resource
    ISysRoleService sysRoleService;
    @Resource
    ISysUserService sysUserService;
    @Resource
    ISysDeptService sysDeptService;
    @Resource
    ISysUserRoleService sysUserRoleService;
    @Resource
    ISysRoleMenuService sysRoleMenuService;
    @Resource
    ISysUserDeptService sysUserDeptService;
    @Resource
    IFileService fileService;
    @Resource
    RoleConvert roleConvert;
    @Resource
    UserConvert userConvert;
    @Resource
    SequenceService sequenceService;
    @Override
    public Boolean add(AddRoleReq req) {
        verifyRoleName(req.getRoleName(),null);
        SysRole sysRole = roleConvert.toSysRole(req);
        sysRole.setRoleCode(sequenceService.generateCode(SequenceEnum.ROLE_CODE_RULE));
        return sysRoleService.save(sysRole);
    }

    @Override
    public Boolean edit(EditRoleReq req) {
        verifyAdmin(req.getRoleId(), "不能修改超管角色");
        verifyRoleName(req.getRoleName(),req.getRoleId());
        SysRole sysRole = sysRoleService.getById(req.getRoleId());
        AssertUtils.isNull(sysRole, ResponseCodeEnum.DATA_FAILED, "未查询到角色数据，无法编辑");
        verifyRoleName(req.getRoleName(), req.getRoleId());
        sysRole.setRoleName(req.getRoleName().trim())
                .setStatus(req.getStatus())
                .setRemark(req.getRemark())
                .setUpdateBy(SecurityUtils.getUserId())
                .setUpdateTime(LocalDateTime.now());
        return sysRoleService.updateById(sysRole);
    }

    @Override
    public Boolean del(Long roleId) {
        verifyAdmin(roleId, "不能删除超管角色");
        SysRole sysRole = sysRoleService.getById(roleId);
        AssertUtils.isNull(sysRole, ResponseCodeEnum.DATA_FAILED, "未查询到角色数据，无法删除");
        AssertUtils.isTrue(sysUserRoleService.isUse(roleId), ResponseCodeEnum.HANDEL_FAILED, "角色已经被使用,无法删除");
        sysRole.setIsDelete(Boolean.TRUE)
                .setUpdateBy(SecurityUtils.getUserId())
                .setUpdateTime(LocalDateTime.now());
        return sysRoleService.updateById(sysRole);
    }

    @Override
    public RoleVo detail(Long roleId) {
        SysRole sysRole = sysRoleService.getById(roleId);
        AssertUtils.isNull(sysRole, ResponseCodeEnum.DATA_FAILED, "未查询到部门数据");
        return roleConvert.toRoleVo(sysRole);
    }

    @Override
    public PageInfo<RoleSimpleVo> pageInfo(QueryRoleReq req) {
        PageHelper.startPage(req.getPageNum(), req.getPageSize());
        List<SysRole> list = searchList(req);
        List<Long> byIdList = list.stream().flatMap(n -> Stream.of(n.getCreateBy(), n.getUpdateBy())).distinct().collect(Collectors.toList());
        PageInfo<SysRole> pageData = new PageInfo<>(list);
        return roleConvert.toRoleSimpleVoPage(pageData, sysUserService.getUserNameMap(byIdList));
    }

    @Override
    public List<BaseSelectVo<Long, String>> allSelectList() {
        QueryWrapper<SysRole> wrapper = new QueryWrapper<>();
        wrapper.eq(SysRole.IS_DELETE, Boolean.FALSE);
        List<SysRole> list = sysRoleService.list(wrapper);
        if (CollectionUtils.isEmpty(list)){
            return new ArrayList<>();
        }
        return list.stream().map(item -> new BaseSelectVo<>(item.getId(), item.getRoleName())).collect(Collectors.toList());
    }

    @Override
    public Boolean authorize(RoleAuthorizeReq req) {
        verifyAdmin(req.getRoleId(), "不能授权超管角色");
        AssertUtils.isTrue(CollectionUtils.isEmpty(req.getMenuIds()), ResponseCodeEnum.HANDEL_FAILED, "请选择菜单");
        SysRole role = sysRoleService.getById(req.getRoleId());
        AssertUtils.isNull(role, ResponseCodeEnum.DATA_FAILED, "未查询到角色数据，无法授权");
        return sysRoleMenuService.saveRoleMenu(req.getRoleId(),req.getMenuIds());
    }

    @Override
    public RoleRelevanceVo getRoleRelevanceVo(Long roleId) {
        RoleRelevanceVo vo = new RoleRelevanceVo();
        SysRole role = sysRoleService.getById(roleId);
        AssertUtils.isNull(role, ResponseCodeEnum.DATA_FAILED, "未查询到角色数据");
        vo.setRoleId(roleId);
        List<Long> menuIds = sysRoleMenuService.getMenuIdsByRoleId(roleId);
        vo.setMenuIds(menuIds);
        //查询用户
        List<Long> userIds = sysUserRoleService.getUserIdsByRoleId(roleId);
        List<SysUser> userList = sysUserService.getUserListByIds(userIds);
        List<UserSimpleVo> userSimpleVos = userConvert.toUserSimpleVoList(userList, new UserTranslateBo(deptMapByUserIds(userIds), fileService.getFileMapBySourceIds(userIds, FileCodeConstants.USER_HEAD_SOURCE_CODE)));
        vo.setUserList(userSimpleVos);
        return vo;
    }

    @Override
    public Boolean delRoleUser(DelRoleUserReq req) {
        return sysUserRoleService.delUserRole(req.getUserId(),req.getRoleId());
    }

    /**
     * 角色名称唯一性校验
     * @param roleName 角色名称
     * @param id 自己的id（用于排除自己）
     */
    private void verifyRoleName(String roleName, Long id) {
        long count = sysRoleService.count(new QueryWrapper<SysRole>()
                .ne(id!=null,SysRole.ID,id)
                .eq(SysRole.ROLE_NAME,roleName.trim())
                .eq(SysRole.IS_DELETE,Boolean.FALSE));
        AssertUtils.isTrue(count>0, ResponseCodeEnum.DATA_FAILED,"角色名称已存在,请检查!");
    }
    /**
     * 校验是否超管
     * @param id
     */
    private void verifyAdmin(Long id,String msg) {
        AssertUtils.isTrue(Constants.ADMIN_ROLE_ID.equals(id), ResponseCodeEnum.HANDEL_FAILED, msg);
    }

    private List<SysRole> searchList(QueryRoleReq req){
        QueryWrapper<SysRole> wrapper = new QueryWrapper<>();
        wrapper.like(StringUtils.hasText(req.getRoleName()), SysRole.ROLE_NAME, req.getRoleName());
        wrapper.eq(req.getStatus() != null, SysRole.STATUS, req.getStatus());
        wrapper.ge(StringUtils.hasText(req.getStartTime()), SysRole.UPDATE_TIME, req.getStartTime());
        wrapper.le(StringUtils.hasText(req.getEndTime()), SysRole.UPDATE_TIME, req.getEndTime());
        wrapper.eq(SysRole.IS_DELETE, Boolean.FALSE);
        wrapper.orderByDesc(SysRole.UPDATE_TIME);
        List<SysRole> list = sysRoleService.list(wrapper);
        return list;
    }
    /**
     * 按用户id获取部门名称翻译集合
     * @param userIds
     * @return
     */
    private Map<Long,String> deptMapByUserIds(List<Long> userIds){
        List<Long> deptIds = sysUserDeptService.getDeptIdsByUserIds(userIds);
        if (org.apache.commons.collections.CollectionUtils.isEmpty(deptIds)){
            return new HashMap<>();
        }
        return sysDeptService.getDeptNameMap(deptIds);
    }
}
